<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>检测 - YOLOv8视频智能检测</title>
    <!-- 外部资源引入 -->
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">

    <!-- Tailwind CSS 配置 -->
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#2563eb',
                        secondary: '#4f46e5',
                        danger: '#ef4444',
                    },
                    fontFamily: {
                        sans: ['Inter', 'system-ui', 'sans-serif'],
                    },
                }
            }
        }
    </script>

    <!-- 自定义工具类 -->
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }

            .shadow-custom {
                box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
            }

            .card-hover {
                transition: transform 0.3s ease, box-shadow 0.3s ease;
            }

            .card-hover:hover {
                transform: translateY(-4px);
                box-shadow: 0 8px 25px rgba(0, 0, 0, 0.12);
            }

            .drag-over {
                border-color: #2563eb;
                background-color: rgba(37, 99, 235, 0.05);
            }
        }
    </style>

    <!-- 主样式 -->
    <style>
        body {
            font-family: 'Inter', system-ui, sans-serif;
            background-color: #f8fafc;
        }

        .upload-area {
            transition: all 0.3s ease;
        }

        .progress-bar {
            transition: width 0.3s ease;
        }

        .gradient-bg {
            background: linear-gradient(135deg, #2563eb 0%, #4f46e5 100%);
        }

        html {
            scroll-behavior: smooth;
        }

        @keyframes fadeIn {
            from {
                opacity: 0;
                transform: translateY(-10px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }

        .fade-in {
            animation: fadeIn 0.3s ease-out;
        }

        .no-scrollbar::-webkit-scrollbar {
            display: none;
        }

        .no-scrollbar {
            -ms-overflow-style: none;
            scrollbar-width: none;
        }

        .result-container {
            transition: opacity 0.5s ease;
        }

        .result-container.hidden {
            opacity: 0;
            display: none;
        }

        .status-dots span {
            animation: bounce 1.4s infinite ease-in-out both;
        }

        .status-dots span:nth-child(1) {
            animation-delay: -0.32s;
        }

        .status-dots span:nth-child(2) {
            animation-delay: -0.16s;
        }

        @keyframes bounce {
            0%, 80%, 100% {
                transform: scale(0);
            }
            40% {
                transform: scale(1.0);
            }
        }

        .detection-box {
            position: absolute;
            border: 2px solid #ef4444;
            box-sizing: border-box;
            pointer-events: none;
        }

        .detection-label {
            position: absolute;
            top: -18px;
            left: 0;
            background-color: #ef4444;
            color: white;
            font-size: 12px;
            padding: 1px 6px;
            border-radius: 2px;
            pointer-events: none;
        }

        .file-upload-btn {
            transition: all 0.3s ease;
        }

        .file-upload-btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 12px rgba(37, 99, 235, 0.2);
        }
    </style>
</head>
<body class="min-h-screen flex flex-col">
<!-- 检测页面内容 -->
<div id="detect-page" class="page-content block container mx-auto px-4 py-8">
    <section class="mb-10">
        <h2 class="text-2xl font-bold mb-6 text-center text-gray-800">视频/图像检测</h2>

        <!-- 上传区域 -->
        <div class="bg-white rounded-xl shadow-lg p-6 mb-8">
            <div id="upload-area"
                 class="upload-area border-2 border-dashed border-gray-300 rounded-lg p-8 text-center transition-all cursor-pointer">
                <div class="mb-4">
                    <i class="fa fa-cloud-upload text-4xl text-gray-400 mb-3"></i>
                    <h3 class="text-lg font-medium text-gray-700 mb-1">拖放文件至此处上传</h3>
                    <p class="text-sm text-gray-500 mb-4">或点击下方按钮选择文件</p>
                    <button id="file-select-btn"
                            class="file-upload-btn bg-blue-600 text-white px-6 py-2 rounded-lg hover:bg-blue-700 transition-colors flex items-center justify-center mx-auto">
                        <i class="fa fa-folder-open mr-2"></i>选择视频/图片
                        <input type="file" id="file-input"
                               accept="video/mp4,video/webm,image/jpeg,image/png,image/jpg"
                               class="hidden"/>
                    </button>
                </div>
                <div class="text-xs text-gray-400">
                    支持格式: MP4, WebM, JPG, PNG<br>
                    最大文件大小: 50MB
                </div>
            </div>
        </div>

        <!-- 文件信息显示 -->
        <div id="file-info" class="hidden bg-blue-50 rounded-xl p-4 mb-6">
            <div class="flex items-start">
                <i id="file-icon" class="fa fa-file-video-o text-blue-600 mt-1 mr-3 text-xl"></i>
                <div class="flex-1">
                    <div class="flex justify-between items-start mb-1">
                        <h4 id="file-name" class="font-medium text-gray-800 truncate"></h4>
                        <button id="remove-file"
                                class="text-gray-400 hover:text-red-500 transition-colors">
                            <i class="fa fa-times"></i>
                        </button>
                    </div>
                    <div class="flex flex-wrap gap-y-1 text-sm text-gray-600">
                        <div id="file-size" class="mr-4">
                            <i class="fa fa-database mr-1"></i>
                            <span></span>
                        </div>
                        <div id="file-duration" class="mr-4">
                            <i class="fa fa-clock-o mr-1"></i>
                            <span></span>
                        </div>
                        <div id="file-resolution" class="mr-4">
                            <i class="fa fa-picture-o mr-1"></i>
                            <span></span>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <!-- 处理按钮 -->
        <div id="processing-controls" class="hidden mb-8">
            <button id="start-processing"
                    class="w-full bg-primary text-white py-3 rounded-lg font-medium shadow-md hover:shadow-lg transition-all flex items-center justify-center">
                <i class="fa fa-play-circle mr-2"></i>开始检测
            </button>
        </div>

        <!-- 进度显示 -->
        <div id="progress-section" class="hidden mb-8">
            <div class="bg-white rounded-xl shadow-md p-6">
                <h3 class="text-lg font-medium text-gray-800 mb-4">处理进度</h3>

                <div class="mb-4">
                    <div class="flex justify-between text-sm mb-1">
                        <span id="progress-text">0%</span>
                        <span id="progress-status">准备中...</span>
                    </div>
                    <div class="h-2 bg-gray-200 rounded-full overflow-hidden">
                        <div id="progress-bar" class="progress-bar h-full bg-primary" style="width: 0%"></div>
                    </div>
                </div>

                <!-- 处理状态指示器 -->
                <div id="status-indicator" class="flex items-center justify-center py-2">
                    <div class="status-dots">
                        <span class="inline-block w-2 h-2 bg-primary rounded-full mx-1"></span>
                        <span class="inline-block w-2 h-2 bg-primary rounded-full mx-1"></span>
                        <span class="inline-block w-2 h-2 bg-primary rounded-full mx-1"></span>
                    </div>
                </div>
            </div>
        </div>

        <!-- 结果展示区域 -->
        <div id="results-section" class="result-container hidden">
            <div class="bg-white rounded-xl shadow-lg p-6 mb-8">
                <div class="flex justify-between items-center mb-6">
                    <h3 class="text-xl font-bold text-gray-800">检测结果</h3>
                    <div class="flex gap-2">
                        <button id="export-result"
                                class="flex items-center px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors">
                            <i class="fa fa-download mr-2"></i>导出结果
                        </button>
                        <button id="new-detection"
                                class="flex items-center px-4 py-2 bg-blue-100 text-blue-700 rounded-lg hover:bg-blue-200 transition-colors">
                            <i class="fa fa-plus mr-2"></i>新检测
                        </button>
                    </div>
                </div>

                <!-- 结果统计 -->
                <div class="grid grid-cols-2 sm:grid-cols-4 gap-4 mb-6">
                    <div class="bg-blue-50 rounded-lg p-4 text-center">
                        <div id="total-detections" class="text-2xl font-bold text-blue-600">0</div>
                        <div class="text-sm text-gray-600">总检测数</div>
                    </div>
                    <div class="bg-yellow-50 rounded-lg p-4 text-center">
                        <div id="loose-bolts" class="text-2xl font-bold text-yellow-600">0</div>
                        <div class="text-sm text-gray-600">松动螺栓</div>
                    </div>
                    <div class="bg-red-50 rounded-lg p-4 text-center">
                        <div id="corrosion-count" class="text-2xl font-bold text-red-600">0</div>
                        <div class="text-sm text-gray-600">腐蚀点</div>
                    </div>
                    <div class="bg-purple-50 rounded-lg p-4 text-center">
                        <div id="danger-level" class="text-2xl font-bold text-purple-600">低</div>
                        <div class="text-sm text-gray-600">危险等级</div>
                    </div>
                </div>

                <!-- 结果可视化 -->
                <div class="relative">
                    <!-- 视频/图片结果显示 -->
                    <div id="result-display" class="relative w-full bg-gray-900 rounded-lg overflow-hidden">
                        <!-- 检测结果图片容器 -->
                        <div id="result-image-container" class="relative hidden">
                            <img id="result-image" class="w-full h-auto max-h-[400px] object-contain" src=""
                                 alt="检测结果">
                            <div id="detection-overlay" class="absolute inset-0"></div>
                        </div>

                        <!-- 视频结果 -->
                        <video id="result-video" class="hidden w-full h-auto max-h-[400px] object-contain" controls>
                            <source src="" type="video/mp4">
                            您的浏览器不支持视频播放
                        </video>

                        <!-- 加载占位符 -->
                        <div id="result-loading"
                             class="absolute inset-0 flex items-center justify-center bg-gray-800 bg-opacity-50">
                            <div class="text-center">
                                <div class="inline-block animate-spin rounded-full h-12 w-12 border-b-2 border-white mb-4"></div>
                                <p class="text-white">加载结果中...</p>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- 检测详情列表 -->
                <div class="mt-6">
                    <h4 class="font-semibold text-gray-800 mb-3">检测详情</h4>
                    <div id="detection-details" class="max-h-[200px] overflow-y-auto p-2 text-sm text-gray-700">
                        <div class="text-center text-gray-400 py-4">
                            <i class="fa fa-info-circle mr-1"></i>无检测详情
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <!-- 处理错误提示 -->
        <div id="error-message" class="hidden bg-red-50 border-l-4 border-red-500 text-red-700 p-4 rounded-r-lg mb-6">
            <div class="flex">
                <div class="flex-shrink-0">
                    <i class="fa fa-exclamation-triangle"></i>
                </div>
                <div class="ml-3">
                    <p id="error-text">处理过程中发生错误，请重试</p>
                </div>
                <div class="ml-auto">
                    <button id="close-error" class="text-red-500 hover:text-red-700">
                        <i class="fa fa-times"></i>
                    </button>
                </div>
            </div>
        </div>
    </section>
</div>

<!-- JavaScript -->
<script>
    document.addEventListener('DOMContentLoaded', function () {
        // 获取DOM元素
        const uploadArea = document.getElementById('upload-area');
        const fileInput = document.getElementById('file-input');
        const fileSelectBtn = document.getElementById('file-select-btn');
        const fileInfo = document.getElementById('file-info');
        const fileName = document.getElementById('file-name');
        const fileSize = document.getElementById('file-size').querySelector('span');
        const fileDuration = document.getElementById('file-duration').querySelector('span');
        const fileResolution = document.getElementById('file-resolution').querySelector('span');
        const fileIcon = document.getElementById('file-icon');
        const removeFileBtn = document.getElementById('remove-file');
        const processingControls = document.getElementById('processing-controls');
        const startProcessingBtn = document.getElementById('start-processing');
        const progressSection = document.getElementById('progress-section');
        const progressBar = document.getElementById('progress-bar');
        const progressText = document.getElementById('progress-text');
        const progressStatus = document.getElementById('progress-status');
        const resultsSection = document.getElementById('results-section');
        const resultVideo = document.getElementById('result-video');
        const resultImage = document.getElementById('result-image');
        const resultImageContainer = document.getElementById('result-image-container');
        const detectionOverlay = document.getElementById('detection-overlay');
        const resultLoading = document.getElementById('result-loading');
        const totalDetections = document.getElementById('total-detections');
        const looseBolts = document.getElementById('loose-bolts');
        const corrosionCount = document.getElementById('corrosion-count');
        const dangerLevel = document.getElementById('danger-level');
        const detectionDetails = document.getElementById('detection-details');
        const exportResultBtn = document.getElementById('export-result');
        const newDetectionBtn = document.getElementById('new-detection');
        const errorMessage = document.getElementById('error-message');
        const errorText = document.getElementById('error-text');
        const closeErrorBtn = document.getElementById('close-error');

        // 存储当前上传的文件
        let currentFile = null;
        let fileType = null; // 'video' or 'image'
        let isProcessing = false;
        let currentPredictions = [];
        let detectionImageBase64 = ''; // 存储带框图像的Base64编码

        // 格式文件大小
        function formatFileSize(bytes) {
            if (bytes < 1024) return bytes + ' B';
            if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + ' KB';
            return (bytes / (1024 * 1024)).toFixed(2) + ' MB';
        }

        // 格式时间
        function formatDuration(seconds) {
            if (isNaN(seconds)) return '-';
            const minutes = Math.floor(seconds / 60);
            const remainingSeconds = Math.floor(seconds % 60);
            return minutes + ':' + (remainingSeconds < 10 ? '0' : '') + remainingSeconds;
        }

        // 重置上传状态
        function resetUpload() {
            currentFile = null;
            fileType = null;
            currentPredictions = [];
            detectionImageBase64 = '';
            fileInput.value = '';
            fileInfo.classList.add('hidden');
            processingControls.classList.add('hidden');
            progressSection.classList.add('hidden');
            resultsSection.classList.add('hidden');
            errorMessage.classList.add('hidden');
            uploadArea.classList.remove('drag-over', 'border-blue-500');

            // 重置媒体元素
            if (resultVideo) {
                resultVideo.pause();
                resultVideo.src = '';
                resultVideo.classList.add('hidden');
            }
            if (resultImage) {
                resultImage.src = '';
                resultImageContainer.classList.add('hidden');
            }
            detectionOverlay.innerHTML = '';
        }

        // 显示文件信息
        function showFileInfo(file) {
            currentFile = file;

            // 设置文件名和大小
            fileName.textContent = file.name;
            fileSize.textContent = formatFileSize(file.size);

            // 判断文件类型
            if (file.type.startsWith('video/')) {
                fileType = 'video';
                fileIcon.className = 'fa fa-file-video-o text-blue-600 mt-1 mr-3 text-xl';
                fileDuration.parentElement.classList.remove('hidden');

                // 获取视频信息
                const video = document.createElement('video');
                video.preload = 'metadata';
                video.onloadedmetadata = function () {
                    window.URL.revokeObjectURL(video.src);
                    fileDuration.textContent = formatDuration(video.duration);
                    fileResolution.textContent = video.videoWidth + '×' + video.videoHeight;
                };
                video.onerror = () => {
                    fileDuration.textContent = '-';
                    fileResolution.textContent = '-';
                };
                video.src = window.URL.createObjectURL(file);
            } else if (file.type.startsWith('image/')) {
                fileType = 'image';
                fileIcon.className = 'fa fa-file-image-o text-green-600 mt-1 mr-3 text-xl';
                fileDuration.parentElement.classList.add('hidden');

                // 获取图片信息
                const img = new Image();
                img.onload = function () {
                    window.URL.revokeObjectURL(img.src);
                    fileResolution.textContent = img.width + '×' + img.height;
                };
                img.onerror = () => fileResolution.textContent = '-';
                img.src = window.URL.createObjectURL(file);
            }

            // 显示文件信息和处理按钮
            fileInfo.classList.remove('hidden');
            processingControls.classList.remove('hidden');
        }

        // 显示进度
        function showProgress(percent, status) {
            progressBar.style.width = percent + '%';
            progressText.textContent = percent + '%';
            progressStatus.textContent = status;
        }

        // 显示错误
        function showError(message) {
            errorText.textContent = message;
            errorMessage.classList.remove('hidden');
            progressSection.classList.add('hidden');
            isProcessing = false;
        }

        // 检查模型状态
        function checkModelStatus() {
            fetch('/api/model-status')
                .then(response => response.json())
                .then(data => {
                    if (!data.data.model_loaded) {
                        console.warn('模型未加载，部分功能不可用');
                    }
                })
                .catch(error => console.error('检查模型状态失败:', error));
        }

        // 上传文件到服务器并获取检测结果
        function uploadFileToServer(file) {
            // 显示进度条
            progressSection.classList.remove('hidden');
            showProgress(0, '正在上传文件...');

            // 创建FormData对象
            const formData = new FormData();
            formData.append('file', file);

            // 发送文件到服务器
            fetch('/api/upload-file', {
                method: 'POST',
                body: formData
            })
                .then(response => {
                    if (!response.ok) throw new Error(`请求失败，状态码: ${response.status}`);
                    return response.json();
                })
                .then(data => {
                    console.log('服务器响应:', data);
                    if (data.code !== 200) throw new Error(data.message || '文件上传失败');

                    showProgress(50, '正在分析文件...');

                    // 存储检测结果和带框图像Base64
                    if (data.data.predictions) {
                        currentPredictions = data.data.predictions;
                        detectionImageBase64 = data.data.file_path; // 后端返回的Base64编码

                        // 延迟显示结果（确保加载完成）
                        setTimeout(showResults, 800);
                    } else if (data.message.includes('模型未加载')) {
                        throw new Error('模型服务暂不可用，请联系管理员');
                    } else {
                        throw new Error('服务器未返回检测结果');
                    }
                })
                .catch(error => {
                    console.error('文件上传/检测失败:', error);
                    showError(`处理失败: ${error.message}`);
                });
        }

        // 显示检测结果
        function showResults() {
            // 统计不同类型的目标数量
            const classCounts = {};
            currentPredictions.forEach(prediction => {
                const className = prediction.class_name || `类别${prediction.class}`;
                classCounts[className] = (classCounts[className] || 0) + 1;
            });

            // 设置结果统计
            const totalCount = currentPredictions.length;
            totalDetections.textContent = totalCount;
            looseBolts.textContent = classCounts['loose_bolt'] || classCounts['松动螺栓'] || 0;
            corrosionCount.textContent = classCounts['corrosion'] || classCounts['腐蚀'] || 0;

            // 设置危险等级
            const looseBoltCount = looseBolts.textContent * 1;
            const corrosionCountValue = corrosionCount.textContent * 1;
            if (looseBoltCount >= 10 || corrosionCountValue >= 15) {
                dangerLevel.textContent = '高';
                dangerLevel.className = 'text-2xl font-bold text-red-600';
            } else if (looseBoltCount >= 5 || corrosionCountValue >= 8) {
                dangerLevel.textContent = '中';
                dangerLevel.className = 'text-2xl font-bold text-orange-600';
            } else {
                dangerLevel.textContent = '低';
                dangerLevel.className = 'text-2xl font-bold text-green-600';
            }

            // 生成检测详情
            let detailsHTML = '';
            if (totalCount === 0) {
                detailsHTML = `
                    <div class="text-center text-gray-400 py-4">
                        <i class="fa fa-info-circle mr-1"></i>未检测到目标
                    </div>
                `;
            } else {
                currentPredictions.forEach((prediction, index) => {
                    const className = prediction.class_name || `类别${prediction.class}`;
                    const confidence = (prediction.confidence * 100).toFixed(1);
                    detailsHTML += `
                    <div class="flex justify-between items-center py-2 border-b border-gray-100">
                        <div class="flex items-center">
                            <span class="inline-block w-2 h-2 rounded-full mr-2 ${className.includes('松动') ? 'bg-yellow-500' : 'bg-red-500'}"></span>
                            <span>${className} ${index + 1}</span>
                        </div>
                        <div class="flex gap-4">
                            <span class="font-medium">${confidence}%</span>
                        </div>
                    </div>
                    `;
                });
            }
            detectionDetails.innerHTML = detailsHTML;

            // 隐藏进度，显示结果
            progressSection.classList.add('hidden');
            resultsSection.classList.remove('hidden');
            resultLoading.classList.add('hidden');

            // 显示带框图像/视频
            if (fileType === 'video') {
                resultVideo.classList.remove('hidden');
                resultVideo.src = window.URL.createObjectURL(currentFile);
                resultVideo.load();
            } else if (fileType === 'image') {
                resultImageContainer.classList.remove('hidden');
                // 直接使用Base64编码显示带框图像
                resultImage.src = detectionImageBase64;
            }

            isProcessing = false;
        }

        // 在图片上绘制检测框
        function drawDetectionBoxes() {
            detectionOverlay.innerHTML = '';
            if (!currentPredictions.length || !currentPredictions[0].hasOwnProperty('bbox')) return;

            // 获取图片缩放比例
            const img = resultImage;
            const scaleX = img.offsetWidth / img.naturalWidth;
            const scaleY = img.offsetHeight / img.naturalHeight;

            // 绘制每个检测框
            currentPredictions.forEach(prediction => {
                const [x, y, width, height] = prediction.bbox;
                const className = prediction.class_name || `类别${prediction.class}`;
                const confidence = (prediction.confidence * 100).toFixed(1);

                // 创建检测框
                const box = document.createElement('div');
                box.className = 'detection-box';
                box.style.left = (x * scaleX) + 'px';
                box.style.top = (y * scaleY) + 'px';
                box.style.width = (width * scaleX) + 'px';
                box.style.height = (height * scaleY) + 'px';

                // 创建标签
                const label = document.createElement('div');
                label.className = 'detection-label';
                label.textContent = `${className} ${confidence}%`;

                box.appendChild(label);
                detectionOverlay.appendChild(box);
            });
        }

        // 绑定事件监听器
        fileSelectBtn.addEventListener('click', () => fileInput.click());
        fileInput.addEventListener('change', (e) => e.target.files[0] && showFileInfo(e.target.files[0]));

        // 拖放事件
        uploadArea.addEventListener('dragover', (e) => {
            e.preventDefault();
            uploadArea.classList.add('drag-over', 'border-blue-500');
        });
        uploadArea.addEventListener('dragleave', () => {
            uploadArea.classList.remove('drag-over', 'border-blue-500');
        });
        uploadArea.addEventListener('drop', (e) => {
            e.preventDefault();
            uploadArea.classList.remove('drag-over', 'border-blue-500');
            e.dataTransfer.files[0] && showFileInfo(e.dataTransfer.files[0]);
        });

        // 移除文件
        removeFileBtn.addEventListener('click', resetUpload);

        // 开始检测
        startProcessingBtn.addEventListener('click', () => {
            if (!currentFile || isProcessing) return;
            isProcessing = true;
            progressSection.classList.remove('hidden');
            errorMessage.classList.add('hidden');
            showProgress(0, '准备上传...');
            uploadFileToServer(currentFile);
        });

        // 导出结果
        exportResultBtn.addEventListener('click', () => {
            const report = {
                filename: currentFile.name,
                timestamp: new Date().toLocaleString(),
                totalDetections: currentPredictions.length,
                looseBolts: looseBolts.textContent * 1,
                corrosionCount: corrosionCount.textContent * 1,
                dangerLevel: dangerLevel.textContent,
                predictions: currentPredictions
            };

            const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(report, null, 2));
            const downloadAnchor = document.createElement('a');
            downloadAnchor.href = dataStr;
            downloadAnchor.download = `detection_result_${Date.now()}.json`;
            document.body.appendChild(downloadAnchor);
            downloadAnchor.click();
            downloadAnchor.remove();
        });

        // 新检测
        newDetectionBtn.addEventListener('click', resetUpload);

        // 关闭错误提示
        closeErrorBtn.addEventListener('click', () => errorMessage.classList.add('hidden'));

        // 点击上传区域选择文件
        uploadArea.addEventListener('click', () => {
            if (fileInfo.classList.contains('hidden')) fileInput.click();
        });

        // 页面卸载清理
        window.addEventListener('beforeunload', () => {
            if (currentFile) window.URL.revokeObjectURL(currentFile);
        });

        // 检查模型状态
        checkModelStatus();
    });
</script>
</body>
</html>